package cc.shacocloud.mirage.utils.file;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.EnumSet;

/**
 * @author 思追(shaco)
 */
public class FilesUtil {
    
    public static final FileAttribute<?>[] NO_FILE_ATTRIBUTES = {};
    
    /**
     * 所有者文件目录权限
     */
    public static final EnumSet<PosixFilePermission> OWNER_DIRECTORY_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
            PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);
    
    /**
     * 所有者文件权限
     */
    public static final EnumSet<PosixFilePermission> OWNER_FILE_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
            PosixFilePermission.OWNER_WRITE);
    
    
    private static final int BUFFER_SIZE = 64 * 1024;
    
    /**
     * 获取文件属性
     *
     * @param fileSystem     文件系统
     * @param ownerReadWrite 所有者读写权限
     * @return {@link FileAttribute}
     */
    public static FileAttribute<?>[] getFileAttributes(@NotNull FileSystem fileSystem, EnumSet<PosixFilePermission> ownerReadWrite) {
        if (!fileSystem.supportedFileAttributeViews().contains("posix")) {
            return NO_FILE_ATTRIBUTES;
        }
        return new FileAttribute<?>[]{PosixFilePermissions.asFileAttribute(ownerReadWrite)};
    }
    
    /**
     * 将 {@link InputStream} 写入 {@link Path}，原本有的内容将被覆盖
     *
     * @param path   {@link Path}
     * @param stream 数据流
     * @throws IOException 写入发生例外！
     */
    public static void writeInputStream(@NotNull Path path, @NotNull InputStream stream) throws IOException {
        // 不存在则创建文件
        if (!Files.exists(path)) {
            FileSystem fileSystem = path.getFileSystem();
            Files.createDirectories(path.getParent(), getFileAttributes(fileSystem, OWNER_DIRECTORY_PERMISSIONS));
            Files.createFile(path, getFileAttributes(fileSystem, OWNER_FILE_PERMISSIONS));
        }
        
        try (InputStream inputStream = stream;
             OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        }
    }
}
